﻿using Furion.DependencyInjection;
using Furion.JsonSerialization;
using FurionApi.Demo.Application.Cache.Enum;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FurionApi.Demo.Application.Cache.Services
{
    public class SysCacheService : ISysCacheService, ISingleton
    {
        private readonly IDistributedCache _cache;

        public SysCacheService(IDistributedCache cache)
        {
            this._cache = cache;
        }

        public IDistributedCache Cache => _cache;

        public async Task<T> GetAsync<T>(string cacheKey)
        {
            var res = await _cache.GetAsync(cacheKey);
            return res == null ? default : JSON.Deserialize<T>(Encoding.UTF8.GetString(res));
        }

        public async Task<string> GetStringAsync(string cacheKey)
        {
            return await _cache.GetStringAsync(cacheKey);
        }

        public async Task RemoveAsync(string key)
        {
            await _cache.RemoveAsync(key);
        }

        public async Task SetAsync(string cacheKey, object value, int timeOutSecond = 0, TimeOutType timeOutType = TimeOutType.Sliding)
        {
            var options = GetOptions(timeOutSecond, timeOutType);
            await _cache.SetAsync(cacheKey, Encoding.UTF8.GetBytes(JSON.Serialize(value)), options);
        }

        public async Task SetStringAsync(string cacheKey, string str, int timeOutSecond = 0, TimeOutType timeOutType = TimeOutType.Sliding)
        {
            var options = GetOptions(timeOutSecond, timeOutType);
            await _cache.SetStringAsync(cacheKey, str, options);
        }

        private static DistributedCacheEntryOptions GetOptions(int timeOutSecond, TimeOutType timeOutType)
        {
            DistributedCacheEntryOptions options = new DistributedCacheEntryOptions();

            if (timeOutSecond > 0)
            {
                if (timeOutType == TimeOutType.Sliding)
                {
                    options.SlidingExpiration =
                        TimeSpan.FromSeconds(timeOutSecond);
                }
                else
                {
                    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeOutSecond);
                }
            }

            return options;
        }
    }
}
